#!/bin/bash

# Filter extra cmake arguments
# This has no effect when building Charm++ without cmake
if [[ "$1" = "@CMAKE_C_COMPILER@" ]]; then shift; fi
if [[ "$1" = "@CMAKE_CXX_COMPILER@" ]]; then shift; fi
if [[ "$1" = "@CMAKE_Fortran_COMPILER@" ]]; then shift; fi

[ -z "$AMPICC" ] && AMPICC="$(basename $0)"
CHARMBIN=$(dirname $0)
CHARMLIB="$CHARMBIN/../lib"
CHARMINC="$CHARMBIN/../include"
. "$CHARMINC/conv-mach-opt.sh"

[ -z "$AMPICC_MODE" ] && AMPICC_MODE='ampi'
VERBOSE=''
STANDALONE=''
GLOBALS=''
GLOBALS_SHARED=''
GLOBALS_FUNCPTR=''
EXPLICIT_COMPILATION=''
BUILD_SHARE=''
PASSTHROUGH_COMPILER_OPTIONS=''

ARGS=''
OBJECT=''

# protect rpath arguments from disappearing due to variable expansion
ORIGIN='\$ORIGIN'

processArgs() {
while [ ! $# -eq 0 ]
do
  arg="$1"
  case "$arg" in
  -showme:command|--showme:command)
     shift
     echo "$CHARMBIN/$AMPICC" $ARGS "$@"
     exit 0
     ;;
  -showme:compile|--showme:compile)
     exit 0
     ;;
  -showme:link|--showme:link)
     exit 0
     ;;
  -showme:incdirs|--showme:incdirs)
     exit 0
     ;;
  -showme:libdirs|--showme:libdirs)
     exit 0
     ;;
  -showme:libs|--showme:libs)
     exit 0
     ;;
  -showme:version|--showme:version)
     echo "AMPI ($AMPICC)"
     exit 0
     ;;
  -showme:help|--showme:help)
     echo "AMPI ($AMPICC)"
     exit 0
     ;;
  -showme:*|--showme:*)
     exit 1
     ;;
  -show*|--show*)
     shift
     echo "$CHARMBIN/$AMPICC" $ARGS "$@"
     exit 0
     ;;
  -v|--version|-print-search-dirs)
     PASSTHROUGH_COMPILER_OPTIONS+=" $arg"
     ;;
  -verbose)
     VERBOSE='true'
     ARGS="$ARGS \"$arg\""
     ;;
  -standalone)
     STANDALONE='true'
     ;;

  -fsglobals)
     GLOBALS='fs'
     GLOBALS_SHARED='1'
     ;;
  -pipglobals)
     GLOBALS='pip'
     GLOBALS_SHARED='1'
     GLOBALS_FUNCPTR='1'
     ;;

  -c)
     EXPLICIT_COMPILATION='true'
     ARGS="$ARGS \"$arg\""
     ;;
  -shared|-G)
     BUILD_SHARE='true'
     ARGS="$ARGS \"$arg\""
     ;;
  -o)
     shift
     OBJECT="$1"
     ;;
  *)
     ARGS="$ARGS \"$arg\""
     ;;
  esac
  shift
done
}

eval processArgs "$AMPI_BUILD_FLAGS" "$@"

# If there are no filename arguments specified, just pass through
# compiler options to charmc. Helps with configure scripts that
# parse the output to detect compiler versions, search paths, etc.
if [[ -z "$ARGS" && -n "$PASSTHROUGH_COMPILER_OPTIONS" ]]; then
  $CHARMBIN/charmc $PASSTHROUGH_COMPILER_OPTIONS
  exit $?
fi

ARGS+=" $PASSTHROUGH_COMPILER_OPTIONS"

Do() {
  [ -n "$VERBOSE" ] && echo "$AMPICC: Executing $@" 1>&2
  eval "$@"
}

if [ "$GLOBALS" = 'fs' ]
then
  if [ "$CMK_SUPPORTS_FSGLOBALS" != '1' ]
  then
    echo "Error: Prerequisites for -fsglobals support were not detected."
    exit 1
  fi
elif [ "$GLOBALS" = 'pip' ]
then
  if [ "$CMK_SUPPORTS_PIPGLOBALS" != '1' ]
  then
    echo "Error: Prerequisites for -pipglobals support were not detected."
    exit 1
  fi
fi

AMPICC_POST_OPTS=''

[ -n "$STANDALONE" ] && ARGS="$ARGS -standalone"

if [ -z "$STANDALONE" ]
then
  [ "$CMK_AMPI_WITH_ROMIO" = '1' ] && ROMIO='-pthread'

  [ "$CMK_SUPPORTS_MEMORY_ISOMALLOC" = '1' ] && ARGS="-memory isomalloc $ARGS"
  ARGS="-module CommonLBs $ARGS"
fi

ARGS+=" -language $AMPICC_MODE"

if [ -n "$GLOBALS" ]
then
  USER_SUFFIX="$CMK_USER_SUFFIX.$CMK_SHARED_SUF"
  if [ -n "$GLOBALS_SHARED" ]
  then
    SHARED_OPTS='-shared'
    [ "$CMK_MACOSX" != '1' ] && SHIM_OPTS='-fPIE' || SHIM_OPTS=''
    SHIM_MAIN_OBJS=''
  else
    SHARED_OPTS=''
    SHIM_OPTS='-fPIE'
    SHIM_MAIN_OBJS="\"$CHARMLIB/ampi_funcptr_shim_main.o\""
  fi

  if [ -n "$GLOBALS_FUNCPTR" -o "$CMK_WINDOWS" = '1' ]
  then
    SHIM_OPTS="$SHIM_OPTS -standalone -DAMPI_USE_FUNCPTR"
    SHIM_OBJS="\"$CHARMLIB/ampi_funcptr_shim.o\" $SHIM_MAIN_OBJS"
    [ "$AMPICC_MODE" = 'ampif' ] && SHIM_OBJS="$SHIM_OBJS \"$CHARMLIB/ampi_funcptr_shim_fortran.o\" \"$CHARMLIB/ampifimpl.o\" \"$CHARMLIB/ampimod.o\""
    LOADER_OBJS="\"$CHARMLIB/ampi_funcptr_loader.o\" $ROMIO"
    ROMIO=''
  else
    SHIM_OBJS=''
    LOADER_OBJS="\"$CHARMLIB/ampi_funcptr_loader_stub.o\""
    [ "$AMPICC_MODE" = 'ampif' ] && LOADER_OBJS="$LOADER_OBJS \"$CHARMLIB/ampif.o\" \"$CHARMLIB/ampifimpl.o\" \"$CHARMLIB/ampimod.o\""
  fi
  [ "$AMPICC_MODE" = 'ampif' ] && SHIM_OBJS="$SHIM_OBJS \"$CHARMLIB/ampi_funcptr_shim_fmpimain.o\""

  if [ -z "$EXPLICIT_COMPILATION" -a -z "$BUILD_SHARE" -a -z "$STANDALONE" ] # if linking an AMPI executable
  then
    # link the user program as its own file
    [ -z "$OBJECT" ] && USEROBJECT="a.out$USER_SUFFIX" || USEROBJECT="${OBJECT%$CMK_POST_EXE}$USER_SUFFIX"
    SHIM_OPTS="$SHIM_OPTS -standalone -Wl,-undefined,dynamic_lookup"
    Do $CHARMBIN/charmc $ARGS $AMPICC_POST_OPTS $SHIM_OPTS $SHIM_OBJS $SHARED_OPTS -o "$USEROBJECT"
    status=$?
    [ $status -ne 0 ] && exit $status

    # set up linking the loader against the runtime
    AMPICC_POST_OPTS="$AMPICC_POST_OPTS -clear-input $LOADER_OBJS \"$CHARMLIB/ampi_globals_$GLOBALS.o\""

    if [ "$GLOBALS" = 'pip' ]
    then
      # look for PiP-glibc
      [ -z "$PIP_GLIBC_INSTALL_DIR" ] && PIP_GLIBC_INSTALL_DIR='/opt/pip'
      pipldquery="$PIP_GLIBC_INSTALL_DIR/lib/ld-*.so"
      set -- $pipldquery
      pipld="$1"
      if [ "$pipld" = "$pipldquery" ]
      then
        echo 'Note: PiP-glibc not found. Maximum virtualization count will be limited.'
        echo '      Please set and export $PIP_GLIBC_INSTALL_DIR appropriately.'
      else
        AMPICC_POST_OPTS="$AMPICC_POST_OPTS -Wl,--dynamic-linker=$pipld"
      fi
    fi
  else
    AMPICC_POST_OPTS="$AMPICC_POST_OPTS $SHIM_OPTS"
    [ -z "$BUILD_SHARE" ] && AMPICC_POST_OPTS="$AMPICC_POST_OPTS $SHARED_OPTS"
  fi
fi

if [ -n "$OBJECT" ]
then
  AMPICC_POST_OPTS="$AMPICC_POST_OPTS -o \"$OBJECT\""
fi

Do $CHARMBIN/charmc -default-to-aout $ARGS $AMPICC_POST_OPTS $ROMIO
status=$?

# Copy ampirun, but do not overwrite it if it already exists.
[ $status -eq 0 ] && cp -n $CHARMBIN/ampirun .

exit $status
